package utils;

import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


public class DateUtils {
    private static final Object lockobj = new Object();
    private static Map<String, ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();
    private static final Map<String, DateTimeFormatter> formatterCache = new HashMap<>();

    private static SimpleDateFormat getSdf(final String pattern) {
        ThreadLocal<SimpleDateFormat> t1 = sdfMap.get(pattern);
        if (t1 == null) {
            synchronized (lockobj) {
                t1 = sdfMap.get(pattern);
                if (t1 == null) {
                    t1 = new ThreadLocal<SimpleDateFormat>() {
                        @Override
                        protected SimpleDateFormat initialValue() {
                            return new SimpleDateFormat(pattern);
                        }
                    };
                    sdfMap.put(pattern, t1);
                }
            }
        }
        return t1.get();
    }

    public static String format(Date date, String pattern) {
        return getSdf(pattern).format(date);
    }

    public static Date parse(String dateStr, String pattern) {
        try {
            return getSdf(pattern).parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getDatePoor(Date endDate, Date nowDate, String h, String m) {

        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        long sec = diff % nd % nh % nm / ns;
        return day * 24 + hour + h + min + m + sec;
    }

    public static String getDatePoorWithDiff(long diff) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        long ns = 1000;
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        long sec = diff % nd % nh % nm / ns;
        return day * 24 + hour + ":" + min + ":" + sec;
    }

    public static String getLocalDatePoor(LocalDateTime itemJoinTime) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 计算两个时间的差值
        Duration duration = Duration.between(itemJoinTime, now);
        // 获取小时、分钟和秒
        int hours = (int) duration.toHours();
        int minutes = (int) (duration.toMinutes() % 60);
        int seconds = (int) duration.getSeconds() % 60;
        // 格式化输出时分秒
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }

    public static Integer getLocalDatePoorWithSec(LocalDateTime itemJoinTime) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 计算两个时间的差值
        Duration duration = Duration.between(itemJoinTime, now);
        // 获取小时、分钟和秒
        return (int) duration.getSeconds();
    }

    public static String getLocalDatePoor(LocalDateTime itemJoinTime, long totalTime) {
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        itemJoinTime = itemJoinTime.plusSeconds(totalTime);
        // 计算两个时间的差值
        Duration duration = Duration.between(now, itemJoinTime);
        // 获取小时、分钟和秒
        int hours = (int) duration.toHours();
        int minutes = (int) (duration.toMinutes() % 60);
        int seconds = (int) duration.getSeconds() % 60;
        // 格式化输出时分秒
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        return String.format("%02d:%02d:%02d", hours, minutes, seconds);
    }


    public static String convertSecondsToTime(String totalSecondsStr) {
        long totalSeconds = Long.parseLong(totalSecondsStr);
        long hours = totalSeconds / 3600;
        long minutes = (totalSeconds % 3600) / 60;
        long seconds = totalSeconds % 60;

        // 使用String.format()来格式化输出，确保双位数显示
        return String.format("%d:%02d:%02d", hours, minutes, seconds);
    }

    public static Time getTimeDiff(Time time1, Time time2) {
        // 将java.sql.Time转换为java.time.LocalTime
        LocalTime localTime1 = time1.toLocalTime();
        LocalTime localTime2 = time2.toLocalTime();
        // 计算两个时间之间的差值，单位为秒
        long secondsBetween = ChronoUnit.SECONDS.between(localTime2, localTime1);
        // 根据差值创建Duration对象
        // 注意：Duration的构建是从起始时间到结束时间，因此这里需要调换顺序
        Duration duration = Duration.ofSeconds(secondsBetween);
        // 将Duration转换回java.sql.Time类型
        // 由于Duration是时间长度，我们需要一个参考时间点来进行转换
        // 这里我们使用时间点"1970-01-01T00:00:00"作为参考（即LocalTime的午夜开始时间）
        LocalTime endTime = LocalTime.MIDNIGHT.plus(duration);
        return Time.valueOf(endTime);
    }

    public static String getMonthStartDay(String startTime) {
        return startTime.split("-")[0] + "-" + startTime.split("-")[1] + "-01";
    }

    /**
     * 根据给定的日期和天数，计算新的日期。
     *
     * @param dateStr 原始日期字符串，格式为 "yyyy-MM-dd"
     * @param days    要往前或往后推的天数，正数表示往后推，负数表示往前推
     * @return 计算后的新日期字符串
     */
    public static String calculateNewDate(String dateStr, int days) {
        DateTimeFormatter formatter = getFormatter("yyyy-MM-dd");
        LocalDate date = LocalDate.parse(dateStr, formatter);
        LocalDate newDate = date.plusDays(days); // 根据天数加减日期
        return newDate.format(formatter); // 返回格式化后的日期字符串
    }

    /**
     * 根据指定的格式返回当前时间的字符串表示。
     *
     * @param pattern 日期时间格式字符串，如 "yyyy-MM-dd HH:mm:ss"
     * @return 格式化后的当前时间字符串
     */
    public static String getCurrentTimeFormatted(String pattern) {
        LocalDateTime now = LocalDateTime.now(); // 获取当前时间
        DateTimeFormatter formatter = getFormatter(pattern); // 创建格式化器
        return now.format(formatter); // 格式化当前时间
    }

    /**
     * 格式化日期的方法。
     *
     * @param date      要格式化的日期。
     * @param formatter 日期格式字符串，例如 "yyyy-MM-dd"。
     * @return 格式化后的日期字符串。
     * @throws IllegalArgumentException 如果日期格式不正确。
     */
    public static String formatDate(LocalDate date, String formatter) {
        try {
            DateTimeFormatter dateTimeFormatter = getFormatter(formatter);
            return date.format(dateTimeFormatter);
        } catch (IllegalArgumentException e) {
            // 处理格式不正确的情况
            throw new IllegalArgumentException("Invalid date format: " + formatter, e);
        }
    }

    public static boolean isValidLocalDate(String date, String format) {
        try {
            DateTimeFormatter formatter = getFormatter(format);
            LocalDate.parse(date, formatter);
            return true;
        } catch (DateTimeParseException e) {
            return false;
        }
    }

    public static long calculateDaysBetweenDates(String dateStr1, String dateStr2) {

        DateTimeFormatter formatter = getFormatter("yyyy-MM-dd");
        LocalDate date1 = LocalDate.parse(dateStr1, formatter);
        LocalDate date2 = LocalDate.parse(dateStr2, formatter);

        return ChronoUnit.DAYS.between(date1, date2);
    }

    public static DateTimeFormatter getFormatter(String pattern) {
        // 检查缓存中是否已经有对应的 DateTimeFormatter 对象
        return formatterCache.computeIfAbsent(pattern, DateTimeFormatter::ofPattern);
    }

    // 计算两个java.util.Date对象之间的天数差
    public static long daysBetween(Date startDate, Date endDate) {
        // 将Date对象转换为毫秒时间戳
        long startMillis = startDate.getTime();
        long endMillis = endDate.getTime();

        // 计算两个时间戳之间的差异，单位为毫秒
        long diffInMillies = endMillis - startMillis;

        // 将毫秒转换为天数
        return TimeUnit.DAYS.convert(diffInMillies, TimeUnit.MILLISECONDS);
    }

    /**
     * 将符合给定格式的日期字符串转换为java.util.Date对象。
     *
     * @param dateString 日期字符串
     * @param pattern    日期格式模式，例如 "yyyy-MM-dd"
     * @return java.util.Date对象
     * @throws ParseException 如果日期字符串与给定格式不匹配，则抛出此异常
     */
    public static Date stringToDate(String dateString, String pattern) throws ParseException {
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        return formatter.parse(dateString);
    }
}
